Skip to content

fix: handle invalid HTTP/2 headers gracefully (#4356)#5077

Closed
mcollina wants to merge 2 commits into
mainfrom
fix/http2-invalid-headers
Closed

fix: handle invalid HTTP/2 headers gracefully (#4356)#5077
mcollina wants to merge 2 commits into
mainfrom
fix/http2-invalid-headers

Conversation

@mcollina
Copy link
Copy Markdown
Member

@mcollina mcollina commented Apr 20, 2026

When session.request() throws synchronously due to invalid HTTP/2 headers (e.g., duplicate headers like "content-type" and "Content-Type"), the error was not being caught, causing an uncaught exception.

The fix wraps all session.request() calls with try-catch blocks. When an error is caught, only the request is errored (via util.errorRequest) and the function returns false. The session is not destroyed because the error is caused by the client sending invalid headers, not the server.

This allows the client to continue using the same session for subsequent requests, and the error is properly caught by user code.

Closes #4356

@mcollina mcollina requested a review from metcoder95 April 20, 2026 16:29
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 81.81818% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.08%. Comparing base (a1d6766) to head (c6bb580).
⚠️ Report is 15 commits behind head on main.

Files with missing lines Patch % Lines
lib/dispatcher/client-h2.js 81.81% 8 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5077      +/-   ##
==========================================
- Coverage   93.10%   93.08%   -0.03%     
==========================================
  Files         110      110              
  Lines       35770    35853      +83     
==========================================
+ Hits        33303    33372      +69     
- Misses       2467     2481      +14     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread lib/dispatcher/client-h2.js Outdated
Comment on lines +534 to +542
// An error here means the server sent invalid HTTP/2 headers
// (e.g., HTTP/1 headers like "http2-settings"). This is a server error.
// We destroy the socket/session and error the request so the client
// can retry with a new connection.
util.errorRequest(client, request, err)
const socket = session[kSocket]
session.destroy(err)
util.destroy(socket, err)
return false
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t know how h2 works, but did this cause other "valid", ongoing requests that use the same socket/session to be interrupted?

When session.request() throws synchronously due to invalid HTTP/2 headers
(e.g., duplicate headers like 'content-type' and 'Content-Type'), the error
was not being caught, causing an uncaught exception.

The fix wraps all session.request() calls with try-catch blocks. When an
error is caught, only the request is errored (via util.errorRequest) and
the function returns false. The session is not destroyed because the error
is caused by the client sending invalid headers, not the server.

This allows the client to continue using the same session for subsequent
requests, and the error is properly caught by user code.

Closes #4356
@mcollina mcollina force-pushed the fix/http2-invalid-headers branch from dcf9d03 to 500eb60 Compare April 21, 2026 09:34
Copy link
Copy Markdown
Member

@metcoder95 metcoder95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests seems, failing; rest lgtm

@mcollina
Copy link
Copy Markdown
Member Author

@metcoder95 PTAL

Copy link
Copy Markdown
Contributor

@cesarvspr cesarvspr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. I read through it and ran it locally.

The fix looks right to me. Wrapping session.request and only erroring the request, while leaving the session alive, matches the existing pattern just above at the upgrade check, and not destroying the session on a client side header mistake seems like the correct call. The second test is a nice regression guard: when I reverted the patch locally it failed exactly as expected, with an uncaughtException and code ERR_HTTP2_HEADER_SINGLE_VALUE, then passed again once restored.

One small thing, please take it or leave it. The first test, "invalid headers should be recoverable", sends two valid GETs and never actually sends an invalid header, so it stays green even with the fix reverted. It looks like the real coverage lives entirely in the second test. If it is useful, that first test could send a bad request, catch the throw, then reuse the same client for a good request, which would prove the session really did recover. Completely optional and non blocking.

Thanks again for sorting this out.

@metcoder95
Copy link
Copy Markdown
Member

just conflicts to solve and ready to merge

@webcarrot
Copy link
Copy Markdown

@mcollina mcollina closed this Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Invalid HTTP2 headers should be recoverable

5 participants